(function($) {
    
    $.fn.ZkMultiSelectWidget = function( settings ) {
	
	settings = $.extend({}, $.fn.ZkMultiSelectWidget.defaults, settings );
	
	var originalSelect = $(this).hide();
        var originalId     = originalSelect.attr('id');
        var optionsSelect  = originalSelect.find('option');
	
	var generalDiv  = $('<div/>')
            .addClass('zk-general-div')
            .attr('id','zk-general-div__' + originalId )
            .css({
		'width':  settings.ZkWidth * 2 + 44 + (settings.ZkRange ? 44 : 0)
	    })
        ;
	
	var descrDiv  = $('<div/>')
            .addClass('zk-descr-div')
            .css({
		'width':  settings.ZkWidth * 2 + 40 + (settings.ZkRange ? 40 : 0)
	    })
        ;
	
	var headerDiv  = $('<div/>')
            .addClass('zk-header-div')
        ;
	
	var leftHeader = $('<div/>')
            .addClass('zk-header')
            .addClass('zk-header-left')
            .css({
		'width':  settings.ZkWidth,
	    })
        ;
	
	var rightHeader = $('<div/>')
            .addClass('zk-header')
            .addClass('zk-header-right')
            .css({
		'margin-left': '40px',
		'width':       settings.ZkWidth - 10,
		'color':       'blue'
	    })
	    .text('Selected')
        ;
        
	var mainDiv  = $('<div/>')
            .addClass('zk-main-div')
        ;
	
	var leftDiv = $('<div/>')
            .addClass('zk-child-div')
            .addClass('zk-child-div-left')
            .css({
		'width':      settings.ZkWidth,
		'height':     settings.ZkHeight,
		'border':     '1px solid #665',
		'background': '#FFFFFF'
	    })
        ;
        
        var rightDiv = $('<div/>')
            .addClass('zk-child-div')
            .addClass('zk-child-div-right')
            .css({
		'width':      settings.ZkWidth,
		'height':     settings.ZkHeight,
		'border':     '1px solid #665',
		'background': '#FFFFFF'
	    })
        ;
        
        var funcDiv = $('<div/>')
            .addClass('zk-child-div')
            .addClass('zk-func-div')
            .css({
		'padding-top': settings.ZkHeight / 2 - 32
	    })
        ;
        
        var rangeDiv = $('<div/>')
            .addClass('zk-child-div')
            .addClass('zk-range-div')
            .css({
		'padding-top': settings.ZkHeight / 2 - 32
	    })
        ;
        
        var leftUl = $('<ul/>')
            .attr('id',originalId + '__left')
        ;
        
        var rightUl = $('<ul/>')
            .attr('id',originalId + '__right')
        ;
        
        var rightAdd = $('<p/>')
            .addClass('zk-p')
            .addClass('zk-right-p')
            .addClass('zk-noact-p')
            .attr('title','Add selected')
            .html('&rsaquo;')
        ;
        
        var leftAdd = $('<p/>')
            .addClass('zk-p')
            .addClass('zk-left-p')
            .addClass('zk-noact-p')
            .attr('title','Remove selected')
            .html('&lsaquo;')
        ;
        
        var topAdd = $('<p/>')
            .addClass('zk-range-p')
            .addClass('zk-top-p')
            .addClass('zk-noact-p')
            .attr('title','Top')
            .html('&#8593;')
        ;
        
        var bottomAdd = $('<p/>')
            .addClass('zk-range-p')
            .addClass('zk-bottom-p')
            .addClass('zk-noact-p')
            .attr('title','Bottom')
            .html('&#8595;')
        ;
	
        var inputSearch  = $('<input class="zk-search-input" />').hide();
        var imageSearch  = $('<img alt="Search" title="Search" src="" />')
	                   .hide();
        var deleteSearch = $('<img alt="Delete" title="Delete" src="" />')
	                   .hide();
	
        if( settings.ZkSearch ){
            leftHeader.append(
                $('<span/>')
                .css({ 'width': settings.ZkWidth })
                .append( imageSearch.show() )
                .append( inputSearch.css({'margin-left':'5px','display':'inline','background':'white','border':'1px solid #999'}).show() )
                .append( deleteSearch )
            );
        }
	
	// LOAD ITEMS
        optionsSelect.each(function(i, opt) {
            var li = $('<li/>');
	    if ($.inArray(parseInt(opt.value), settings.ZkOptionsDisabled) != -1) {
		li.addClass('zk-disabled');
	    }
            li.data('idx',opt.value);
            li.append(opt.text);
            if( opt.selected ) rightUl.append(li);
            else leftUl.append(li);
        });
	
        // SEARCH LEFT FUNCTION
        var searchV = false;
        var toid = false;
        var ZkSearch = function() {
            if (searchV == inputSearch.val()) return;
            searchV = inputSearch.val();
	    setTimeout(function() {
	        leftUl.children().hide();
	        if (searchV == "") {
		    leftUl.children().show();
		    deleteSearch.hide();
	        } else {
		    leftUl.children().each(function() {
		        var myText = $(this).text();
		        var find = myText.toUpperCase().indexOf(searchV.toUpperCase());
		        if (find != -1){
		            $(this).show();
		        }
	            });
		    if (leftUl.children().filter(':visible').length == 0){
                        inputSearch.css({'border': '1px red solid'});
                    }
		    deleteSearch.css({'cursor':'pointer','display':'inline'}).show();
	        }
	    }, 5);
        };

        // REMOVE FILTER ON SEARCH FUNCTION
        deleteSearch.click(function(e) {
            e.preventDefault();
	    clearTimeout(toid);
	    inputSearch.val("").removeAttr("style");
	    ZkSearch();
	    return false;
        });

        // ON CHANGE TEXT INPUT
        inputSearch.keyup(function() {
	    clearTimeout(toid);
	    toid = setTimeout(ZkSearch, 200);
        });
	
	
	generalDiv.append(headerDiv.append(leftHeader).append(rightHeader));
        leftDiv.append(leftUl);
        rightDiv.append(rightUl);
        funcDiv.append(rightAdd).append(leftAdd);
        mainDiv.append(leftDiv).append(funcDiv).append(rightDiv);
	if (settings.ZkRange) {
	    rightHeader.css({'width':settings.ZkWidth + 40 - 10});
	    mainDiv.append(rangeDiv.append(topAdd).append(bottomAdd));
	}
        generalDiv.append(mainDiv);
	if (settings.ZkDescr) {
	    generalDiv.append(descrDiv);
	}
        originalSelect.after(generalDiv);
	
        $('#zk-general-div__' + originalId + ' .zk-main-div .zk-child-div ul li').click(function(e){
            e.preventDefault();
	    if (settings.ZkDescr) {
		triggerDescr($(this).data('idx'));
	    }
	    var ind = $(this).index();
	    triggerClickLi($(this),e.ctrlKey,e.shiftKey,ind);
	    triggerLeltRight();
        });
	
	var triggerLeltRight = function(){
	    $('#zk-general-div__' + originalId + ' .zk-main-div .zk-child-div-left ul li').each(function() {
		if ($(this).hasClass('zk-li-act')) {
		    rightAdd.removeClass('zk-noact-p').addClass('zk-act-p');
		    return false;
		}
		rightAdd.removeClass('zk-act-p').addClass('zk-noact-p');
	    });
	    $('#zk-general-div__' + originalId + ' .zk-main-div .zk-child-div-right ul li').each(function() {
		if ($(this).hasClass('zk-li-act')) {
		    leftAdd.removeClass('zk-noact-p').addClass('zk-act-p');
		    return false;
		}
		leftAdd.removeClass('zk-act-p').addClass('zk-noact-p');
	    });
	};

	var triggerClickLi = function(li,ctrl,shift,ind){
	    if (li.hasClass('zk-disabled')) return;
	    var thisUl = li.parent();
	    var thisAllLi = thisUl.find('li');
	    thisAllLi.removeClass('zk-li-act-nofocus');
	    li.removeClass('zk-li-act-nofocus');
	    if (thisUl.parent().hasClass('zk-child-div-right')) {
		topAdd.removeClass('zk-noact-p').addClass('zk-act-p');
		bottomAdd.removeClass('zk-noact-p').addClass('zk-act-p');
	    } else {
		topAdd.removeClass('zk-act-p').addClass('zk-noact-p');
		bottomAdd.removeClass('zk-act-p').addClass('zk-noact-p');
	    }
	    if (true == ctrl) {
		li.toggleClass('zk-li-act');
	    } else if (true == shift) { 
		if (ind > -1) {
		    var findOk = false;
		    var xStart = ind;
		    var xFinish = ind;
		    for (var i = ind; i >= 0; i--) {
			var tempEl = thisAllLi.eq(i);
			if (tempEl.hasClass('zk-li-act')) {
			    xStart = tempEl.index();
			    findOk = true;
			    i = -1;
			}
		    }
		    if (!findOk) {
			var allLenght = thisAllLi.last().index();
			for (var i = ind; i <= allLenght; i++) {
			    var tempEl = thisAllLi.eq(i);
			    if (tempEl.hasClass('zk-li-act')) {
			        xFinish = tempEl.index();
			        findOk = true;
			        i = allLenght + 1;
			    }
			}
		    } 
		    thisAllLi.slice(xStart,xFinish+1).addClass('zk-li-act');
		}
	    } else {
	        thisAllLi.removeClass('zk-li-act');
		li.toggleClass('zk-li-act');
	    }
	    
	    var act = thisUl.parent().hasClass('zk-child-div-left') ? 'left' : 'right';
	    var noact = 'left' == act ? 'right' : 'left';
	    $('#zk-general-div__' + originalId + ' .zk-main-div .zk-child-div-' + noact + ' ul .zk-li-act')
	    .addClass('zk-li-act-nofocus');
	};
	
	$('#zk-general-div__' + originalId + ' .zk-main-div .zk-p').click(function(e){
	    if ($(this).hasClass('zk-act-p')) {
		$(this).removeClass('zk-act-p').addClass('zk-noact-p');
                if( $(this).hasClass('zk-right-p') ){
                    var sel = leftUl.find('.zk-li-act').addClass('zk-li-act-nofocus');
                    rightUl.append(sel);
                    if( sel.length > 0 ){
                        leftAdd.addClass('zk-act-p').removeClass('zk-noact-p');
                    }
                } else if( $(this).hasClass('zk-left-p') ){
                    var sel = rightUl.find('.zk-li-act').addClass('zk-li-act-nofocus');
                    leftUl.append(sel);
                    if( sel.length > 0 ){
                        rightAdd.addClass('zk-act-p').removeClass('zk-noact-p');
                    }
                }
                updateOriginalSelect();
	    }
	});
	
	$('#zk-general-div__' + originalId + ' .zk-main-div .zk-range-p').click(function(e){
	    if ($(this).hasClass('zk-act-p')) {
		var selectedDx = $('#zk-general-div__' + originalId + ' .zk-main-div .zk-child-div-right ul .zk-li-act');
		if ($(this).hasClass('zk-top-p')) {
	            var prev = selectedDx.first().prev();
	            selectedDx.each(function() {
		        $(this).insertBefore(prev);
	            });
		} else if ($(this).hasClass('zk-bottom-p')) {
	            var next = selectedDx.last().next();
	            selectedDx.each(function() {
		        $(this).insertAfter(next);
	            });
		}
		updateOriginalSelectAfterRange();
	    }
	});
	
        var updateOriginalSelect = function(){
            rightUl.children().each(function(i,li){
                $("#" + originalId + " option[value='" + $(li).data('idx') + "']").attr('selected',true);
            });
            leftUl.children().each(function(i,li){
                $("#" + originalId + " option[value='" + $(li).data('idx') + "']").attr('selected',false);
            });
        };
	
        var updateOriginalSelectAfterRange = function(){
            rightUl.children().each(function(i,li){
	        $("#" + originalId + " option[value='" + $(li).data('idx') + "']").remove();
	        var _option = $('<option value="' + $(li).data('idx') + '">' + $(li).text() + '</option>')
	        .attr('selected',true);
                originalSelect.append(_option);
            });
        }
	
	var triggerDescr = function(id){
	    if (settings.ZkDescr.route) {
		$.get(Routing.generate(settings.ZkDescr.route,{'id':id}),
		    function(data){
                    $('#zk-general-div__' + originalId + ' .zk-descr-div').html(data);
                });
	    }
	};
    }
    
    
    $.fn.ZkMultiSelectWidget.defaults = {
        ZkHeight: 200,
        ZkWidth:  200,
        ZkSearch: false,
        ZkRange:  false,
	ZkDescr:  false,
	ZkOptionsDisabled: []
    };
    
})(jQuery);
